namespace SimpleWebServices.Configuration
{
    using System;
    using System.Configuration;
    using System.Xml;
    using System.Xml.XPath;
    using SimpleWebServices.Web.UI.Html.Elements;
    using Xunit;

    public sealed class HtmlElementConfigurationFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<HtmlElementConfiguration>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("html")
                .Implements<IConfigurationSectionHandler>()
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            HtmlElementConfiguration actual = (
                "<html whitespace='true'>" +
                    "<elements>" +
                        "<element type='SimpleWebServices.Web.UI.Html.Elements.Anchor, SimpleWebServices' />" +
                        "<element type='SimpleWebServices.Web.UI.Html.Elements.TextInput, SimpleWebServices' />" +
                    "</elements>" +
                "</html>").Deserialize<HtmlElementConfiguration>();

            Assert.True(actual.WhiteSpace);
            Assert.IsType<Anchor>(actual.Elements[0]);
            Assert.IsType<TextInput>(actual.Elements[1]);
        }

        [Fact]
        public void deserializeEmpty()
        {
            HtmlElementConfiguration actual = "<html />".Deserialize<HtmlElementConfiguration>();

            Assert.NotNull(actual);

            Assert.False(actual.WhiteSpace);
            Assert.Empty(actual.Elements);
        }

        [Fact]
        public void serialize()
        {
            HtmlElementConfiguration obj = new HtmlElementConfiguration
            {
                WhiteSpace = true,
                Elements = new HtmlElementCollection
                {
                    new Anchor()
                }
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            Assert.True((bool)navigator.Evaluate("1=count(/html[@whitespace='true']/elements/element[@type='SimpleWebServices.Web.UI.Html.Elements.Anchor, SimpleWebServices'])"));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new HtmlElementConfiguration());
        }

        [Fact]
        public void prop_Elements()
        {
            Assert.True(new PropertyExpectations(typeof(HtmlElementConfiguration).GetProperty("Elements"))
                .XmlElement("elements")
                .TypeIs<HtmlElementCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_WhiteSpace()
        {
            Assert.True(new PropertyExpectations(typeof(HtmlElementConfiguration).GetProperty("WhiteSpace"))
                .XmlAttribute("whitespace")
                .IsAutoProperty<bool>()
                .Result);
        }

        [Fact]
        public void op_Deserialize_string_string_string()
        {
            string expected = "test";
            string actual = (HtmlElementConfiguration.Deserialize("input", "text", "<input type='text' value='" + expected + "' />") as TextInput).Value;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_Deserialize_stringEmpty_string_string()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => HtmlElementConfiguration.Deserialize(string.Empty, "type", "<div />"));
        }

        [Fact]
        public void op_Deserialize_stringNull_string_string()
        {
            Assert.Throws<ArgumentNullException>(() => HtmlElementConfiguration.Deserialize(null as string, "type", "<div />"));
        }

        [Fact]
        public void op_Deserialize_string_stringEmpty_string()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => HtmlElementConfiguration.Deserialize("div", string.Empty, "<div />"));
        }

        [Fact]
        public void op_Deserialize_string_stringNull_string()
        {
            string expected = "test";
            string actual = HtmlElementConfiguration.Deserialize("div", null as string, "<div id='" + expected + "' />").ToElement().Id;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_Deserialize_string_string_stringEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => HtmlElementConfiguration.Deserialize("input", "text", string.Empty));
        }

        [Fact]
        public void op_Deserialize_string_string_stringNull()
        {
            Assert.Throws<ArgumentNullException>(() => HtmlElementConfiguration.Deserialize("input", "text", null as string));
        }

        [Fact]
        public void op_Settings()
        {
            Assert.NotNull(HtmlElementConfiguration.Settings());
        }

        [Fact]
        public void op_Settings_string()
        {
            Assert.NotNull(HtmlElementConfiguration.Settings("simplewebservices/html"));
        }

        [Fact]
        public void op_Create_object_object_XmlNodeNull()
        {
            HtmlElementConfiguration obj = (new HtmlElementConfiguration() as IConfigurationSectionHandler).Create(null, null, null as XmlNode) as HtmlElementConfiguration;

            Assert.NotNull(obj);
        }

        [Fact]
        public void op_Create_object_object_XmlNodeEmpty()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml("<html />");

            HtmlElementConfiguration obj = (new HtmlElementConfiguration() as IConfigurationSectionHandler).Create(null, null, xml.DocumentElement) as HtmlElementConfiguration;

            Assert.NotNull(obj);
        }

        [Fact]
        public void op_Create_object_object_XmlNode()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(
                "<html whitespace='true'>" +
                    "<elements>" +
                        "<element type='SimpleWebServices.Web.UI.Html.Elements.Anchor, SimpleWebServices' />" +
                        "<element type='SimpleWebServices.Web.UI.Html.Elements.TextInput, SimpleWebServices' />" +
                    "</elements>" +
                "</html>");

            HtmlElementConfiguration obj = (new HtmlElementConfiguration() as IConfigurationSectionHandler).Create(null, null, xml.DocumentElement) as HtmlElementConfiguration;

            Assert.True(obj.WhiteSpace);
            Assert.IsType<Anchor>(obj.Elements[0]);
            Assert.IsType<TextInput>(obj.Elements[1]);
        }

        [Fact]
        public void op_Create_object_object_XmlNode_invalidType()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(
                "<html>" +
                    "<elements>" +
                        "<element type='System.DateTime' />" +
                    "</elements>" +
                "</html>");

            Assert.Throws<ConfigurationErrorsException>(() => (new HtmlElementConfiguration() as IConfigurationSectionHandler).Create(null, null, xml.DocumentElement));
        }
    }
}